前面一天我們介紹了 OpenCV 的基本功能像是圖像讀取、顯示、保存、色彩空間轉換..那我們接著進入我們的主題,在第一天時我們提到了 Adobe 的物品置入技術,你可能會想這有什麼難的?不就是直接把物品去背丟進去嗎?沒錯這樣的理解或許是對的~不過因為 3D 物品將會涉及更多的細節像是在光影下材質的不同表現,所以我們在今天先用 2D 圖像來玩玩吧!不過不用擔心這些內容在之後的鐵人賽都會有更深入的探討,我們開始吧!
我們可以先來看看結果圖吧!
首先一樣歡迎大家前往 Kaggle 的 Notebook 來做練習
收先先來引入必要的套件吧!
import cv2
print(cv2.__version__)
接著我們來讀取圖片吧!
background_path = '/kaggle/input/combine-picture-dataset/kitchen.png'
poster_path = '/kaggle/input/combine-picture-dataset/lisa.jpg'
# 讀取背景和海報圖片
background = cv2.imread(background_path)
poster = cv2.imread(poster_path, cv2.IMREAD_UNCHANGED) # 保留 Alpha 通道
# 如果海報沒有 Alpha 通道,添加一個
if poster.shape[2] == 3:
poster = cv2.cvtColor(poster, cv2.COLOR_BGR2BGRA)
接著透過調整 Alpha 通道的方式去調整透明度。
# 確保圖像有Alpha通道
if poster.shape[2] != 4:
poster = cv2.cvtColor(image, cv2.COLOR_BGR2BGRA)
# 將Alpha值調整到0-255的範圍
alpha_factor = int(alpha * 255)
# 調整alpha通道
poster[:, :, 3] = alpha_factor
那因為我們蒙娜麗莎的圖片大小太大了所以需要去調整海報大小,這邊使用縮放的方式去進行調整。
# 計算縮放比例,使海報高度為背景高度的一半
scale = background.shape[0] / (4 * poster.shape[0])
new_width = int(poster.shape[1] * scale)
new_height = int(poster.shape[0] * scale)
poster = cv2.resize(poster, (new_width, new_height), interpolation=cv2.INTER_AREA)
接著我們貼上指定的區域吧!這下方的程式目標就是要確保海報不會超出畫面。
# 確保海報不會超出背景邊界
x, y = position
if x < 0: x = 0
if y < 0: y = 0
if x + poster.shape[1] > background.shape[1]: x = background.shape[1] - poster.shape[1]
if y + poster.shape[0] > background.shape[0]: y = background.shape[0] - poster.shape[0]
position = (x, y)
再來創建遮罩並進行 Alpha 混合。為甚麼這邊要做遮罩和 Alpha 混合呢?
下方的程式碼邏輯如下,首先先用 np.zeros 創建了一個全黑的遮罩(全透明),然後用前景圖像的 Alpha 通道填充該遮罩。接著提取圖像區域和計算混合比例 roi(Region of Interest)定義了背景中前景圖像將被放置的位置,Alpha 計算了前景圖像中每個像素的透明度(0 到 1 之間),使用公式 result = (1 - alpha) * roi + alpha * poster_bgr 進行混合。這個公式將背景和前景圖像按照 Alpha 通道的比例進行加權平均。
mask = np.zeros(background.shape[:2], dtype=np.uint8)
mask[y:y+poster.shape[0], x:x+poster.shape[1]] = poster[:,:,3]
poster_bgr = poster[:,:,:3]
roi = background[y:y+poster.shape[0], x:x+poster.shape[1]]
alpha = mask[y:y+poster.shape[0], x:x+poster.shape[1]] / 255.0
result = (1 - alpha[:,:,np.newaxis]) * roi + alpha[:,:,np.newaxis] * poster_bgr
最後一步就是保存結果啦~
background[y:y+poster.shape[0], x:x+poster.shape[1]] = result.astype(np.uint8)
cv2.imwrite('/kaggle/working/result.png', background)
你可以看到圖像是被貼上去了,透過 Alpha 混合有稍微讓合成效果比起隨意貼上更加真實且自然,但可以看到在光影以及透視的感覺並沒有這麼的好因此我們接下來將會針對這些問題繼續探討下去,歡迎繼續追蹤我們的鐵人賽文章~
如有任何問題也可以下方留言Q&A!